import datetime

from ctaBase import *
from ctaTemplate import *
from indicators import Indicators
from utils import MinKLineGenerator

class My_RSI_Demo(CtaTemplate):
    """RSI指标策略demo
    """
    def __init__(self):
        super().__init__()

        # 参数映射表
        self.paramMap = {
            'periodX': 'K线周期X',
            'tradetype': '交易类型X',
            'order_volume': '下单手数',
            # 'istime': '是否选择时间段',
            # 'startdt': '开始时间',
            # 'enddt': '结束时间',
            # 'istlimit': '是否限制次数',
            # 'tlimit': '次数限制',
            'exchange': '交易所',
            'vtSymbol': '合约代码',
        }

        # 变量映射表
        self.varMap = {
            'trading': '交易中',
            # 'excTimes': '执行次数',
            'pos': '持仓',
        }
        
        # RSI参数及区间
        self.R = 6
        # self.S = 12
        # self.I = 24
        self.rup = 80
        self.rdm = 20

        
        self.periodX = 1      # k线周期X
        self.tradetype = 'B' # 交易方向  B 买 S 卖
  
        # self.istime = False
        # self.startdt = '09:00:00'
        # self.enddt = '15:00:00'

        # self.istlimit = False
        # self.tlimit = 10
        # # 填写的时候一定要加''，来确保该字段为string,如'119016'
        # self.investor = ''


        # self.widgetClass = KLWidget
        # self.widget: KLWidget = None
        # self.indicators: Indicators = None
        # self.kline_generator: MinKLineGenerator = None

         # 策略参数
        self.exchange = ""
        self.vtSymbol = ""
        self.order_volume = 1  # 下单手数
        self.pay_up = 0 # 超价, 买 + 卖 -
 
        self.tick = None        

        self.current_rsi = 0  # 当前 K 线rsi数值
        self.prev_rsi = 0  # 上一根 K 线rsi数值

        self.trading = False

    def onStart(self):
        """启动策略（必须由用户继承实现）"""
        # 获取1分钟k线数据
        self.bm = BarManager(self.onBar, self.periodX, onXminBar=self.onXminBar)
     
        self.am = ArrayManager(size=100)
        self.loadBar(1,func=self.onBar)

        super().onStart()

    def onBar(self, bar):
        """收到Bar推送"""
        self.bm.updateBar(bar)  # 更新 1 分钟 bar 数据
     
        if self.tradeDate != bar.date:
            self.tradeDate = bar.date


    def onXminBar(self, bar):
        self.bar = bar # 接收到 bar 数据推送，赋值给全局变量
        self.output('onXminBar',bar.__dict__)

        # 记录数据
        # if not self.am.updateBar(bar):
        #     return

        # # 计算指标
        # self.calc_indicator(bar)

        # # 计算信号
        # self.calc_signal(bar)

        # # 信号执行
        # self.exec_signal()


   
    def onTick(self, tick):
        """收到行情TICK推送"""
        super().onTick(tick)

        # self.output('onTick',tick.__dict__)
        # 过滤涨跌停和集合竟价
        if tick.lastPrice == 0 or tick.askPrice1 == 0 or tick.bidPrice1 == 0:
            return
        self.tick = tick # 将收到的 tick 赋值给全局变量
        # 更新
        self.bm.updateTick(tick)

    def calc_indicator(self,bar) -> None:
        """计算指标数据"""
        currentArr = self.am.rsi(self.R,array=True)
        # self.output('M1当前rsi6参数值:', currentArr)
        self.output('M1当前rsi参数值:', currentArr[-1],'上一个rsi6参数值:', currentArr[-2])
        self.current_rsi,self.prev_rsi = round(currentArr[-1], 2),round(currentArr[-2],2) # 对指标的数值进行四舍五入
    

    def calc_signal(self, bar) -> None:
        """计算交易信号"""

        # 判断是否要进行交易
        self.buy_signal = (self.current_rsi > self.rdm) & (self.prev_rsi <= self.rdm)
        self.short_signal = (self.current_rsi < self.rup) & (self.prev_rsi >= self.rup)
        # 交易价格
        self.long_price = bar.close  #做多操作时的买入价格
        self.short_price = bar.close #做空操作时的卖出价格
        # if self.buy_signal or self.short_signal: 
            # 5分钟卖出信号会每钟打印一次  这个问题需要处理掉 5分钟卖出信号只使用一次
            # self.output('M1_RSI交易信号：',
            #             'buy:',self.buy_signal,
            #             'short:',self.short_signal,
            #             'M1的rsi值:',self.current_rsi,
            #             'M1上一分钟的值:',self.prev_rsi,
            #             '当前价格:',bar.close,
            #             '交易时间',bar.datetime)


    def exec_signal(self) -> None:
        """简易交易信号执行"""
        position = self.get_position(self.vtSymbol)

        # 挂单未成交
        if self.orderID is not None:
            self.cancelOrder(self.orderID)

        self.signal = 0

        if position.net_position == 0:  #: 当前无仓位
            # 买开，卖开
            if self.short_signal and self.tradetype == 'S':
                self.signal = abs(self.short_price)

                if self.trading is False:
                    return

                self.orderID = self.short(
                    price=(price := self.short_price - self.pay_up),
                    volume=self.order_volume
                )
                self.output(f'卖出开仓信号价格: {price}')

            elif self.buy_signal and self.tradetype == 'B':
                self.signal = self.long_price

                if self.trading is False:
                    return

                self.orderID = self.buy(
                    price=(price := self.long_price + self.pay_up),
                    volume=self.order_volume
                )
                self.output(f'买入开仓信号价格: {price}')

        elif position.net_position > 0 and self.buy_signal and self.tradetype == 'B':  #: 持有多头仓位
                self.signal = self.long_price

                if self.trading is False:
                    return

                self.orderID = self.buy(
                    price=(price := self.long_price + self.pay_up),
                    volume=self.order_volume
                )
                self.output(f'买入开仓信号价格: {price}')

        elif position.net_position < 0 and self.short_signal and self.tradetype == 's':  #: 持有空头仓位
                self.signal = abs(self.short_price)

                if self.trading is False:
                    return

                self.orderID = self.short(
                    price=(price := self.short_price - self.pay_up),
                    volume=self.order_volume
                )
                self.output(f'卖出开仓信号价格: {price}')

    
    def onTrade(self, trade, log=True):
        """成交回调"""
        super().onTrade(trade, log)

    def onStop(self):
        """停止策略（必须由用户继承实现）"""
        super().onStop()